/**
 *Copyright (c) 2024 watereyes
 * workflow is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan
 * PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */
package com.koron.workflow.common.util;


import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.apache.commons.lang3.StringUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.awt.Rectangle;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author qingfeng
 * @description: TODO
 * @date 2020/4/8 15:04
 */
public class FileUtils {

    private static final Logger logger = LoggerFactory.getLogger(FileUtils.class);

    /**
     * 添加文件返回id.
     * 把上传的文件存系统配置的路径，并往tblfile表添加记录,最后返回添加记录后的ID
     *
     * @param file
     * @return
     */
    public static void addFile(MultipartFile file, String Path) {
        File root = new File(Path);
        Calendar now = Calendar.getInstance();
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
        String ym = "" + now.get(Calendar.YEAR) + (now.get(Calendar.MONTH) + 1);
        root = new File(root, ym);
        if (root.exists() && root.isFile()) {
            root.delete();
        }
        if (!root.exists()) {
            root.mkdirs();
        }
        Random random = new Random();
        String filename = df.format(now.getTime()) + random.nextInt(100);
        root = new File(root, filename);
        try {
            file.transferTo(root);
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void startHandle(List<FlowNode> l, Element e) {
        StartEvent startEvent = new StartEvent();
        startEvent.setId(e.getAttributeValue("id"));
        startEvent.setName(e.getAttributeValue("name"));

        ExtensionElement startExtensionElement = new ExtensionElement();
        startExtensionElement.setName("activiti:operation");

        ExtensionAttribute extensionAttribute = new ExtensionAttribute("transform");
        extensionAttribute.setValue(e.getAttributeValue("transform"));
        startExtensionElement.addAttribute(extensionAttribute);

        ExtensionAttribute codeAttribute = new ExtensionAttribute("code");
        extensionAttribute.setValue(e.getAttributeValue("code"));
        startExtensionElement.addAttribute(codeAttribute);

        List<ExtensionElement> startLE = new ArrayList<ExtensionElement>();
        startLE.add(startExtensionElement);

        Map<String, List<ExtensionElement>> startEES = new HashMap<String, List<ExtensionElement>>();
        startEES.put("", startLE);
        // extensionElements
        startEvent.setExtensionElements(startEES);

        l.add(startEvent);
    }

    public static void endHandle(List<FlowNode> l, Element e) {
        EndEvent endEvent = new EndEvent();
        endEvent.setId(e.getAttributeValue("id"));
        endEvent.setName(e.getAttributeValue("name"));

        ExtensionElement endExtensionElement = new ExtensionElement();
        endExtensionElement.setName("activiti:operation");

        ExtensionAttribute extensionAttribute = new ExtensionAttribute("code");
        extensionAttribute.setValue(e.getAttributeValue("code"));
        endExtensionElement.addAttribute(extensionAttribute);

        List<ExtensionElement> le = new ArrayList<ExtensionElement>();
        le.add(endExtensionElement);

        Map<String, List<ExtensionElement>> ees = new HashMap<String, List<ExtensionElement>>();
        ees.put("", le);
        // extensionElements
        endEvent.setExtensionElements(ees);

        l.add(endEvent);
    }

    public static void subFlowNodeHandle(String setCode, List<FlowNode> l, Element e){
        UserTask subFlowNode = new UserTask();
        subFlowNode.setName(e.getAttributeValue("name"));
        subFlowNode.setId(e.getAttributeValue("id"));
        ExtensionElement subFlowExtensionElement = new ExtensionElement();
        subFlowExtensionElement.setName("activiti:operation");
        List<String> subFlowList = new ArrayList<String>();
        subFlowList.add("type"); // 类型
        subFlowList.add("sub_flow"); // 子流程编号
        subFlowList.add("code"); // 编号
        for (String s : subFlowList) {
            ExtensionAttribute extensionAttribute = new ExtensionAttribute(s);
            extensionAttribute.setValue(getValue(setCode, s, e));
            subFlowExtensionElement.addAttribute(extensionAttribute);
        }
        List<ExtensionElement> subFlowLE = new ArrayList<ExtensionElement>();
        subFlowLE.add(subFlowExtensionElement);
        Map<String, List<ExtensionElement>> subFlowEES = new HashMap<String, List<ExtensionElement>>();
        subFlowEES.put("", subFlowLE);
        // extensionElements
        subFlowNode.setExtensionElements(subFlowEES);
        // userTask.setAttributes(attributes);
        l.add(subFlowNode);
    }

    public static void draftNodeHandle(String setCode, List<FlowNode> l, Element e) {
        UserTask draftNode = new UserTask();
        draftNode.setName(e.getAttributeValue("name"));
        draftNode.setId(e.getAttributeValue("id"));
        String tmp = e.getAttributeValue("candidate");
        draftNode.setCandidateUsers(Arrays.asList(tmp.split(",")));
        ExtensionElement draftNodeExtensionElement = new ExtensionElement();
        draftNodeExtensionElement.setName("activiti:operation");
        List<String> draftList = new ArrayList<String>();
        draftList.add("type"); // 类型
        draftList.add("code"); // 编号
        draftList.add("notice_way"); // 通知方式
        draftList.add("attachment"); // 审批意见中上传附件
        draftList.add("notice_draft_man"); // 通知起草人
        draftList.add("form_id"); // 表单ID
        draftList.add("can_update_nodes"); // 可修改的节点
        draftList.add("must_update_nodes"); // 必须修改的节点
        draftList.add("candidate");//默认处理人
        draftList.add("filter_rule"); // 过滤规则
        draftList.add("auto_pick_rule"); // 自动选人规则
        draftList.add("approval_criteria"); // 审批基准
        for (String s : draftList) {
            ExtensionAttribute extensionAttribute = new ExtensionAttribute(s);
            extensionAttribute.setValue(getValue(setCode, s, e));
            draftNodeExtensionElement.addAttribute(extensionAttribute);
        }
        List<ExtensionElement> draftLE = new ArrayList<ExtensionElement>();
        draftLE.add(draftNodeExtensionElement);
        Map<String, List<ExtensionElement>> draftEES = new HashMap<String, List<ExtensionElement>>();
        draftEES.put("", draftLE);
        // extensionElements
        draftNode.setExtensionElements(draftEES);
        // userTask.setAttributes(attributes);
        l.add(draftNode);
    }

    public static void noticeNodeHandle(String setCode, List<FlowNode> l, Element e) {
        UserTask noticeNode = new UserTask();
        noticeNode.setName(e.getAttributeValue("name"));
        noticeNode.setId(e.getAttributeValue("id"));
        String tmp = e.getAttributeValue("candidate");
//        noticeNode.setCandidateUsers(split(tmp));
        noticeNode.setCandidateUsers(Arrays.asList(tmp.split(",")));
        ExtensionElement noticeNodeExtensionElement = new ExtensionElement();
        noticeNodeExtensionElement.setName("activiti:operation");

        List<String> noticeList = new ArrayList<String>();
        noticeList.add("type"); // 类型
        noticeList.add("code"); // 编号
        noticeList.add("operator"); // 默认处理人
        noticeList.add("notice_way"); // 通知方式
        noticeList.add("null_operator_skip"); // 为空跳过
        noticeList.add("double_skip"); // 身份重复跳过
        noticeList.add("attachment"); // 附件
        noticeList.add("form_id"); // 表单id
        noticeList.add("filter_rule"); // 过滤规则
        noticeList.add("auto_pick_rule"); // 自动选择规则
        noticeList.add("approval_criteria"); // 审批基准
        noticeList.add("candidate"); // 处理人
        for (String s : noticeList) {
            ExtensionAttribute extensionAttribute = new ExtensionAttribute(s);
            extensionAttribute.setValue(getValue(setCode, s, e));
            noticeNodeExtensionElement.addAttribute(extensionAttribute);
        }

        List<ExtensionElement> noticeLE = new ArrayList<ExtensionElement>();
        noticeLE.add(noticeNodeExtensionElement);

        Map<String, List<ExtensionElement>> noticeEES = new HashMap<String, List<ExtensionElement>>();
        noticeEES.put("", noticeLE);
        // extensionElements
        noticeNode.setExtensionElements(noticeEES);

        // userTask.setAttributes(attributes);
        l.add(noticeNode);
    }

    private static String getValue(String setCode, String s, Element e) {
        String[] string;
        Integer value = 0;
        switch (s) {
            case "notice_way":{
                string = e.getAttributeValue(s).split(",");
                if (string[0].equals("true")) {
                    value = value + 1; // 待办
                }
                if (string[1].equals("true")) {
                    value = value + 2; // 邮件
                }
                if (string[2].equals("true")) {
                    value = value + 4; // 短信
                }
                return value.toString();
            }
            case "options":{
                string = e.getAttributeValue(s).split(",");
                if (string[0].equals("true")) {
                    value = value + 1; // 待办
                }
                if (string[1].equals("true")) {
                    value = value + 2; // 邮件
                }
                if (string[2].equals("true")) {
                    value = value + 4; // 短信
                }
                if (string[3].equals("true")) {
                    value = value + 8; // 短信
                }
                if (string[4].equals("true")) {
                    value = value + 16; // 短信
                }
                return value.toString();
            }
            case "":{
            	
            }
            case "circulation_mode":{
            	 String model = e.getAttributeValue(s);
            	 return StringUtils.isEmpty(model) ? "1" : model;
            }
            case "null_operator_skip":{
            	return e.getAttributeValue(s);
            }
            case "sub_flow":{
            	String subFlow = e.getAttributeValue(s);
            	 return setCode + "_" + subFlow;
            }
            case "double_skip":{
            	return e.getAttributeValue(s);
            }
            case "attachment":{
                if (e.getAttributeValue(s).equals("true"))
                    return "0";
                if (e.getAttributeValue(s).equals("false"))
                    return "1";
                break;
            }
            case "urge_operator":{
            	 break;
            }
            case "notice_draft_man":{
            	 break;
            }
            case "auto_skip":{
                string = e.getAttributeValue(s).split(",");
                value = Integer.valueOf(StringUtils.isNotEmpty(string[0]) ? string[0] : "0") * 24 * 60
                        + Integer.valueOf(StringUtils.isNotEmpty(string[1]) ? string[1] : "0") * 60
                        + Integer.valueOf(StringUtils.isNotEmpty(string[2]) ? string[2] : "0");
                return value.toString();
            }
            default:
                return e.getAttributeValue(s);
        }
        return "";
    }

    public static void approveNodeHandle(String setCode, List<FlowNode> l, Element e, List<SequenceFlow> sequenceFlow) {
        UserTask approveNode = new UserTask();
        approveNode.setName(e.getAttributeValue("name"));
        approveNode.setId(e.getAttributeValue("id"));
        String tmp = e.getAttributeValue("candidate");
        approveNode.setCandidateUsers(Arrays.asList(tmp.split(",")));

        ExtensionElement approveNodeExtensionElement = new ExtensionElement();
        approveNodeExtensionElement.setName("activiti:operation");

        List<String> approveList = new ArrayList<String>();
        approveList.add("type"); // 类型
        //approveList.add("operator"); // 默认处理人
        approveList.add("code"); // 编号
        approveList.add("communicators"); // 沟通人
        approveList.add("null_operator_skip"); // 处理人为空跳过
        approveList.add("double_skip"); // 身份重复跳过
        approveList.add("circulation_mode"); // 流转方式
        approveList.add("filter_rule"); // 过滤规则
        approveList.add("auto_pick_rule"); // 自动选人规则
        approveList.add("approval_criteria"); // 审批基准
        approveList.add("notice_way"); // 通知方式
        approveList.add("attachment"); // 审批意见中上传附件
        approveList.add("options"); // 自定义操作
        approveList.add("remisable_nodes"); // 可驳回的节点
        approveList.add("jumpernodes"); // 可跳转的节点
        approveList.add("can_update_nodes"); // 可修改的节点
        approveList.add("must_update_nodes"); // 必须修改的节点
        approveList.add("urge_operator"); // 催办处理人
        approveList.add("notice_draft_man"); // 通知起草人
        approveList.add("auto_skip"); // 自动跳过
        approveList.add("form_id"); // 表单ID
        approveList.add("candidate");//默认处理人
        for (String s : approveList) {
            ExtensionAttribute extensionAttribute = new ExtensionAttribute(s);
            extensionAttribute.setValue(getValue(setCode, s, e));
            approveNodeExtensionElement.addAttribute(extensionAttribute);
        }
        List<ExtensionElement> approveLE = new ArrayList<ExtensionElement>();
        approveLE.add(approveNodeExtensionElement);

        Map<String, List<ExtensionElement>> approveEES = new HashMap<String, List<ExtensionElement>>();
        approveEES.put("", approveLE);
        approveNode.setExtensionElements(approveEES);
        switch (e.getAttributeValue("circulation_mode").replaceAll(",", "")) {
            // 并行
            case "1":
                break;
            // 串行
            case "2":
                MultiInstanceLoopCharacteristics m2 = new MultiInstanceLoopCharacteristics();
                m2.setSequential(true);
                m2.setLoopCardinality("${Loop" + e.getAttributeValue("id").replaceAll("-", "") + "_User_Size}");
                m2.setInputDataItem("${Loop" + e.getAttributeValue("id").replaceAll("-", "") + "_User_List}");
                m2.setElementVariable("user" + e.getAttributeValue("id").replaceAll("-", ""));
                m2.setCompletionCondition("${Loop" + e.getAttributeValue("id").replaceAll("-", "") + "_User_Size == nrOfCompletedInstances}");
                approveNode.setLoopCharacteristics(m2);
                break;
            // 会审
            case "3":
                MultiInstanceLoopCharacteristics m3 = new MultiInstanceLoopCharacteristics();
                m3.setSequential(false);
                m3.setLoopCardinality("${Loop" + e.getAttributeValue("id").replaceAll("-", "") + "_User_Size}");
                m3.setInputDataItem("${Loop" + e.getAttributeValue("id").replaceAll("-", "") + "_User_List}");
                m3.setElementVariable("user" + e.getAttributeValue("id").replaceAll("-", ""));
                m3.setCompletionCondition("${Loop" + e.getAttributeValue("id").replaceAll("-", "") + "_User_Size == nrOfCompletedInstances}");
                approveNode.setLoopCharacteristics(m3);
                break;
            default:
                break;
        }

        // 可跳转的节点
        List<String> jumpernodes = null;
        if (e.getAttributeValue("jumpernodes") != null && !e.getAttributeValue("jumpernodes").equals("")) {
            jumpernodes = Arrays.asList(e.getAttributeValue("jumpernodes").split(","));
        }
        if (jumpernodes != null && jumpernodes.size() > 0) {
            for (int i = 0; i < jumpernodes.size(); i++) {
                SequenceFlow s = new SequenceFlow();
                s.setSourceRef(e.getAttributeValue("id"));
                s.setTargetRef(jumpernodes.get(i));
                sequenceFlow.add(s);
            }
        }

        // 可驳回的节点
        List<String> remisablenodes = null;
        if (e.getAttributeValue("remisable_nodes") != null && !e.getAttributeValue("remisable_nodes").equals("")) {
            remisablenodes = Arrays.asList(e.getAttributeValue("remisable_nodes").split(","));
        }

        if (remisablenodes != null && remisablenodes.size() > 0) {
            for (int i = 0; i < remisablenodes.size(); i++) {
                SequenceFlow s = new SequenceFlow();
                s.setSourceRef(e.getAttributeValue("id"));
                s.setTargetRef(remisablenodes.get(i));
                sequenceFlow.add(s);
            }
        }

        l.add(approveNode);
    }

    public static void gatewayexHandle(List<FlowNode> l, Element e) {
        ExclusiveGateway exclGetway = new ExclusiveGateway();
        exclGetway.setId(e.getAttributeValue("id"));
        exclGetway.setName(e.getAttributeValue("name"));

        ExtensionElement extensionElement = new ExtensionElement();
        extensionElement.setName("activiti:operation");

        ExtensionAttribute extensionAttribute = new ExtensionAttribute("code");
        extensionAttribute.setValue(e.getAttributeValue("code"));
        extensionElement.addAttribute(extensionAttribute);

        List<ExtensionElement> le = new ArrayList<ExtensionElement>();
        le.add(extensionElement);

        Map<String, List<ExtensionElement>> ees = new HashMap<String, List<ExtensionElement>>();
        ees.put("", le);
        // extensionElements
        exclGetway.setExtensionElements(ees);

        l.add(exclGetway);
    }

    public static void gatewaypaHandle(List<FlowNode> l, Element e) {
        ParallelGateway parallgateway = new ParallelGateway();
        parallgateway.setId(e.getAttributeValue("id"));
        parallgateway.setName(e.getAttributeValue("name"));

        ExtensionElement extensionElement = new ExtensionElement();
        extensionElement.setName("activiti:operation");

        ExtensionAttribute extensionAttribute = new ExtensionAttribute("code");
        extensionAttribute.setValue(e.getAttributeValue("code"));
        extensionElement.addAttribute(extensionAttribute);

        List<ExtensionElement> le = new ArrayList<ExtensionElement>();
        le.add(extensionElement);

        Map<String, List<ExtensionElement>> ees = new HashMap<String, List<ExtensionElement>>();
        ees.put("", le);
        // extensionElements
        parallgateway.setExtensionElements(ees);

        l.add(parallgateway);
    }

    public static void gatewayinHandle(List<FlowNode> l, Element e) {
        InclusiveGateway inclusiveGateway = new InclusiveGateway();
        inclusiveGateway.setId(e.getAttributeValue("id"));
        inclusiveGateway.setName(e.getAttributeValue("name"));

        ExtensionElement extensionElement = new ExtensionElement();
        extensionElement.setName("activiti:operation");

        ExtensionAttribute extensionAttribute = new ExtensionAttribute("code");
        extensionAttribute.setValue(e.getAttributeValue("code"));
        extensionElement.addAttribute(extensionAttribute);

        List<ExtensionElement> le = new ArrayList<ExtensionElement>();
        le.add(extensionElement);

        Map<String, List<ExtensionElement>> ees = new HashMap<String, List<ExtensionElement>>();
        ees.put("", le);
        // extensionElements
        inclusiveGateway.setExtensionElements(ees);

        l.add(inclusiveGateway);
    }

    public static void lineHandle(List<SequenceFlow> l, Element e) {
        SequenceFlow s = new SequenceFlow();
        s.setSourceRef(e.getAttributeValue("start"));
        s.setTargetRef(e.getAttributeValue("end"));
        String expression = e.getAttributeValue("condition_exps").replaceAll("&lt;", "<").replaceAll("&gt;", ">").replaceAll("&#39;", "'").replaceAll("&quot;", "\"");

        /*
         * if(expression==null||expression.equals("")) { expression =
         * "${message==1}"; }
         */
        s.setConditionExpression(expression); // 表达式

        ExtensionElement lineExtensionElement = new ExtensionElement();
        lineExtensionElement.setName("activiti:operation");

        List<String> lineList = new ArrayList<String>();
        lineList.add("count"); // 顺序
        lineList.add("code"); // 编号

        for (String sl : lineList) {
            ExtensionAttribute extensionAttribute = new ExtensionAttribute(sl);
            extensionAttribute.setValue(e.getAttributeValue(sl));
            lineExtensionElement.addAttribute(extensionAttribute);
        }

        List<ExtensionElement> lineLE = new ArrayList<ExtensionElement>();
        lineLE.add(lineExtensionElement);

        Map<String, List<ExtensionElement>> lineEES = new HashMap<String, List<ExtensionElement>>();
        lineEES.put("", lineLE);
        // extensionElements
        s.setExtensionElements(lineEES);
        l.add(s);

    }

    /**
     * 将svg字符串转化为 MultipartFile
     * 将我们自己定义的xml文件，转换成对应的bpmn文件
     *
     * @param processId
     * @param workFlow
     * @param design
     * @return
     * @throws IOException
     * @throws JDOMException
     */
    public static String svgStringToBpmnString(String processCode, String processName, String setCode, String workFlow, String design) throws IOException, JDOMException {
        SAXBuilder xmlBuilder = new SAXBuilder();
        Reader reader = new StringReader(design);
        Document xmlDoc = xmlBuilder.build(reader);
        Element root = xmlDoc.getRootElement();// 获得根节点
        // 实例化BpmnModel对象
        BpmnModel bpmnModel = new BpmnModel();
        Process process = new Process();
        process.setId(setCode + "_" + processCode);
        process.setName(processName);
        // 生成 开始、结束、用户任务
        List<Element> g = root.getChildren("g");
        List<FlowNode> l = new ArrayList<FlowNode>();
        List<SequenceFlow> sequenceFlow = new ArrayList<SequenceFlow>();
        for (Element e : g) {
            switch (e.getAttributeValue("type")) {
                case "start":
                    startHandle(l, e);
                    break;
                case "end":
                    endHandle(l, e);
                    break;
                case "draftNode":
                    draftNodeHandle(setCode, l, e);
                    break;
                case "noticeNode":
                    noticeNodeHandle(setCode, l, e);
                    break;
                case "subFlowNode":
                    subFlowNodeHandle(setCode, l,e);
                    break;
                case "approveNode":
                    approveNodeHandle(setCode, l, e, sequenceFlow);
                    break;
                case "gatewayex": // 排他网关
                    gatewayexHandle(l, e);
                    break;
                case "gatewaypa": // 并行网关
                    gatewaypaHandle(l, e);
                    break;
                case "gatewayin": // 融合网关
                    gatewayinHandle(l, e);
                    break;
                case "line": // 连线
                    lineHandle(sequenceFlow, e);
                    break;
            }
        }

        // 生成 节点与连线之间的关系 并添加节点
        for (FlowNode f : l) {
            for (SequenceFlow s : sequenceFlow) {
                List<SequenceFlow> outgoingFlows = new ArrayList<SequenceFlow>();
                List<SequenceFlow> incomingFlows = new ArrayList<SequenceFlow>();
                if (s.getSourceRef().equals(f.getId())) {
                    outgoingFlows.add(s);
                }
                if (s.getTargetRef().equals(f.getId())) {
                    incomingFlows.add(s);
                }
                f.setOutgoingFlows(outgoingFlows);
                f.setIncomingFlows(incomingFlows);
            }
            process.addFlowElement(f);
        }

        // 添加连线
        for (SequenceFlow s : sequenceFlow) {
            process.addFlowElement(s);
        }

        bpmnModel.addProcess(process);
        BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();

        byte[] convertToXML = bpmnXMLConverter.convertToXML(bpmnModel);
        return new String(convertToXML,"utf-8");
    }


    public static Rectangle getRectangle(String design) throws IOException, JDOMException {
        SAXBuilder xmlBuilder = new SAXBuilder();
        Reader reader = new StringReader(design);
        Document xmlDoc = xmlBuilder.build(reader);
        Element root = xmlDoc.getRootElement();// 获得根节点
        // 生成 开始、结束、用户任务
        List<Element> g = root.getChildren("g");
        List<FlowNode> l = new ArrayList<FlowNode>();
        List<SequenceFlow> sequenceFlow = new ArrayList<SequenceFlow>();
        int minX = -1;
        int minY = -1;
        int maxX = 0;
        int maxY = 0;
        Pattern p = Pattern.compile("matrix\\(\\s*[-\\.\\d]*\\s*,\\s*[-\\.\\d]*\\s*,\\s*[-\\.\\d]*\\s*,\\s*[-\\.\\d]*\\s*,\\s*([-\\.\\d]*)\\s*,\\s*([-\\.\\d]*)\\s*\\)");
        for (Element e : g) {
            String transform = e.getAttributeValue("transform");
            if (transform != null && !transform.isEmpty()) {
                Matcher m = p.matcher(transform);
                if (m.find()) {
                    maxX = Math.max(maxX, (int)Double.parseDouble(m.group(1)));
                    maxY = Math.max(maxY, (int)Double.parseDouble(m.group(2)));
                    if (minX == -1) {
                        minX = (int)Double.parseDouble(m.group(1));
                    } else
                        minX = Math.min(minX, (int)Double.parseDouble(m.group(1)));
                    if (minY == -1) {
                        minY = (int)Double.parseDouble(m.group(2));
                    } else
                        minY = Math.min(minY, (int)Double.parseDouble(m.group(2)));
                }
            }
        }
        minX -= 20;
        minY -= 20;
        maxX += 240;
        maxY += 80;
        minX = minX < 0 ? 0 : minX;
        minY = minY < 0 ? 0 : minY;
        Rectangle rect = new Rectangle(minX, minY, maxX - minX, maxY - minY);
        return rect;
    }

}
